package com.rpay.web.exception;

import com.rpay.common.enums.PcsResultCode;
import com.rpay.common.exception.PcsRunTimeException;
import com.rpay.common.util.LoggerUtil;
import com.rpay.common.vo.PcsResult;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;

/**
 * Title：
 * Description
 *
 * @author fxg06 on 2018/4/19
 * @version 1.0
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {Exception.class})
    public PcsResult defaultErrorHandler(HttpServletRequest req, Exception exception) throws Exception {
        String method = req.getMethod();

        PcsResult pcsResult = new PcsResult();
        if (exception instanceof PcsRunTimeException) {
            // 业务返回
            PcsRunTimeException pcsRunTimeException = (PcsRunTimeException) exception;
            pcsResult.setCode(pcsRunTimeException.getErrorCode());
            pcsResult.setMessage(pcsRunTimeException.getMessage());
            PcsResultCode resultCode = PcsResultCode.valueOf(pcsRunTimeException.getErrorCode());
            pcsResult.setDesc(resultCode.getDetail());
        } else if (exception instanceof BindException) {
            // form validate exception
            BindingResult bindingResult = ((BindException) exception).getBindingResult();
            String error = appendError(bindingResult);
            LoggerUtil.error(error);
            pcsResult.setErrorCode(PcsResultCode.ERROR_OPERATE);
            pcsResult.setDesc(PcsResultCode.ERROR_OPERATE.getDetail());
        } else if (exception instanceof HttpRequestMethodNotSupportedException) {
            LoggerUtil.warn("Request method '{}' not supported", method);
            pcsResult.setErrorCode(PcsResultCode.METHOD_NOT_SUPPORT);
            pcsResult.setDesc(PcsResultCode.METHOD_NOT_SUPPORT.getDetail());
        } else if (exception instanceof NoHandlerFoundException) {
            LoggerUtil.warn("no handler found");
            pcsResult.setErrorCode(PcsResultCode.NOT_FOUND_HANDLER);
            pcsResult.setDesc(PcsResultCode.NOT_FOUND_HANDLER.getDetail());
        } else if (exception instanceof MissingServletRequestParameterException) {
            // 参数缺失
            MissingServletRequestParameterException missingReqParamExp = (MissingServletRequestParameterException) exception;
            pcsResult.setErrorCode(PcsResultCode.PARAM_LOSE);
            pcsResult.setMessage(missingReqParamExp.getParameterName() + PcsResultCode.PARAM_LOSE.getDesc());
            pcsResult.setDesc(PcsResultCode.NOT_FOUND_HANDLER.getDetail());
        } else if (exception instanceof MethodArgumentTypeMismatchException) {
            //参数类型不匹配
            MethodArgumentTypeMismatchException methodArgumentTypeMismatchException = (MethodArgumentTypeMismatchException) exception;
            pcsResult.setErrorCode(PcsResultCode.PARAM_LOSE);
            pcsResult.setMessage(methodArgumentTypeMismatchException.getName() + PcsResultCode.PARAM_TYPE_NOT_SUPPORT.getDesc());
            pcsResult.setDesc(PcsResultCode.PARAM_TYPE_NOT_SUPPORT.getDetail());
        } else if (exception instanceof ConstraintViolationException) {
            ConstraintViolationException constraintViolationExp = (ConstraintViolationException) exception;
            ConstraintViolation constraintViolation = constraintViolationExp.getConstraintViolations().iterator().next();
            if (constraintViolation != null) {
                pcsResult.setMessage(constraintViolation.getMessage());
            }
        } else if (exception instanceof MethodArgumentNotValidException) {
            ///参数验证
            BindingResult bindingResult = ((MethodArgumentNotValidException) exception).getBindingResult();
            String error = this.appendError(bindingResult);
            pcsResult.setErrorCode(PcsResultCode.PARAM_INVALID);
            pcsResult.setMessage(error);
            pcsResult.setDesc(PcsResultCode.PARAM_INVALID.getDetail());
        } else {
            exception.printStackTrace();
            LoggerUtil.error("operation failed: exception={}",
                    exception.getMessage());
            pcsResult.setErrorCode(PcsResultCode.ERROR_OPERATE);
            pcsResult.setDesc(PcsResultCode.ERROR_OPERATE.getDetail());
        }

        return pcsResult;
    }

    private String appendError(BindingResult bindingResult) {
        StringBuffer sb = new StringBuffer();
        if (bindingResult.hasErrors()) {
            List<FieldError> errors = bindingResult.getFieldErrors();
            for (FieldError error : errors) {
                sb.append(error.getDefaultMessage() + ";");
            }
        }
        return sb.toString();
    }
}
